/**
 * 校验
 *
 * 先前的验证是通过bind的时候执行一次验证条件的筛选，然后全部加入观察者（$watch）--在触发正则条件的时候讲文案统一加入到$validation
 * 中,然后在使用的页面通过遍历validation的方式逐一弹出提示，现在由于有判断条件根据用户交互而改变的需求，因此只执行一次的bind无法满足
 */

import Vue from 'vue';
import * as utils from './utils.js';

const ctx = '@@Validator'; //eslint-disable-line

const isServer = true;
// === base ===

let validate = function() {
        // console.log(`【validator】${this.vm._uid}.doUpdate！！！ `, JSON.stringify(this.expression), this, this.field);
        if (!this) return;
        // if (this.watchs && this.watchs.length) [].forEach.call(this.watchs, v => { v(); });
        // this.watchs = []; // 清除所有绑定事件，这个不能删，避免重复绑定多次执行。。。
        this.field = this['validate_id'] || this.vm._uid;
        Vue.$validation[this.field] = {};
        if (this.field) {
            if (!Vue.$validation[this.field]) Vue.$validation[this.field] = Vue.prototype.$validation[this.field] = {}; // 初始化
            if (this.expression.required) _validateRequired.call(this, this.vm.value);
            if (this.expression.minLength || this.expression.maxLength) _validateLength.call(this, this.vm.value);
            if (this.expression.numbers) _validateNumbers.call(this, this.vm.value);
            if (this.expression.text) _validateText.call(this, this.vm.value);
        }
    },
    _getMsg = function(tag, def) {
        let msg = '';
        if (typeof this.expression[tag] === 'string') {
            msg = this.expression[tag];
        } else if (this.expression[tag]['message'] && typeof this.expression[tag]['message'] === 'string') {
            msg = this.expression[tag]['message'];
        } else {
            msg = def;
        }
        return msg;
    },
    _validateRequired = function(newVal) {
        // 监听输入与否
        /** newVal可能是数字，那么下面的判断 newVal.length就会出问题，所以将数字转换为字符串验证 Modify By 刘俊俊 2018.6.11 */
        newVal = String(newVal);
        if (newVal && newVal.length && !newVal.match(/^\s*$/g)) {
            // 如果存在，删除标识，如果不存在，写入提示语（或true）,这里我添加了一个不能全为空格的判断---孙硕；
            delete Vue.$validation[this.field]['required'];
            delete Vue.prototype.$validation[this.field]['required'];
        } else {
            let msg = _getMsg.call(this, 'required', '您有未录入的数据哦~');
            Vue.$validation[this.field]['required'] = Vue.prototype.$validation[this.field]['required'] = msg;
        }
        // console.log(`【validator】${this.vm._uid}.doUpdate！！！ `, Vue.prototype.$validation);
    },
    _validateLength = function(newVal) {
        // 监听输入长度
        if (newVal && this.expression.minLength) {
            let min =
                typeof this.expression.minLength === 'number'
                    ? this.expression.minLength
                    : this.expression.minLength.rule;
            if (newVal.length && newVal.length >= min) {
                delete Vue.$validation[this.field]['minLength'];
                delete Vue.prototype.$validation[this.field]['minLength'];
            } else {
                let msg = _getMsg.call(this, 'minLength', '至少输入' + min + '字哦~');
                Vue.$validation[this.field]['minLength'] = Vue.prototype.$validation[this.field]['minLength'] = msg;
            }
        }
        if (newVal && this.expression.maxLength) {
            let max =
                typeof this.expression.maxLength === 'number'
                    ? this.expression.maxLength
                    : this.expression.maxLength.rule;
            if (newVal.length && newVal.length < max) {
                delete Vue.$validation[this.field]['maxLength'];
                delete Vue.prototype.$validation[this.field]['maxLength'];
            } else {
                let msg = _getMsg.call(this, 'maxLength', '最多输入' + max + '字哦~');
                Vue.$validation[this.field]['maxLength'] = Vue.prototype.$validation[this.field]['maxLength'] = msg;
            }
        }
        if (!newVal && !this.expression.required) {
            delete Vue.$validation[this.field]['minLength'];
            delete Vue.prototype.$validation[this.field]['minLength'];
            delete Vue.$validation[this.field]['maxLength'];
            delete Vue.prototype.$validation[this.field]['maxLength'];
        }
    },
    _validateNumbers = function(newVal) {
        // 监听输入长度
        if (newVal && this.expression.numbers) {
            if (utils.validateNumbers(newVal)) {
                delete Vue.$validation[this.field]['numbers'];
                delete Vue.prototype.$validation[this.field]['numbers'];
            } else {
                let msg = _getMsg.call(this, 'numbers', '只能输入数字哦~');
                Vue.$validation[this.field]['numbers'] = Vue.prototype.$validation[this.field]['numbers'] = msg;
            }
        }
        if (!newVal && !this.expression.required) {
            delete Vue.$validation[this.field]['numbers'];
            delete Vue.prototype.$validation[this.field]['numbers'];
        }
    },
    _validateText = function(newVal) {
        // 监听输入长度
        if (newVal && this.expression.text) {
            if (utils.validateText(newVal)) {
                delete Vue.$validation[this.field]['text'];
                delete Vue.prototype.$validation[this.field]['text'];
            } else {
                let msg = _getMsg.call(this, 'text', '不能包含特殊字符哦~');
                Vue.$validation[this.field]['text'] = Vue.prototype.$validation[this.field]['text'] = msg;
            }
        }
        if (!newVal && !this.expression.required) {
            delete Vue.$validation[this.field]['text'];
            delete Vue.prototype.$validation[this.field]['text'];
        }
    };

// === init ===

let Validator = {
        bind(el, binding, vnode) {
            // console.warn('执行一次bind钩子，全局validation为', Vue.$validation, vnode.context);
            if (typeof binding.value === 'undefined') return;
            el[ctx] = {
                el,
                vm: vnode.context,
                expression: binding.value,
                validate_id: binding.value.key || vnode.context._uid
            };
            const args = arguments;
            el[ctx].vm.$nextTick(() => {
                setTimeout(() => {
                    validate.call(el[ctx], args);
                }, 0);
            });
        },
        componentUpdated(el, binding, vnode) {
            // console.warn('组件更新了，当前的全局validation为', Vue.$validation);
            if (typeof binding.value === 'undefined') return;
            el[ctx] = {
                el,
                vm: vnode.context,
                expression: binding.value,
                validate_id: binding.value.key || vnode.context._uid
            };
            const args = arguments;
            el[ctx].vm.$nextTick(() => {
                setTimeout(() => {
                    validate.call(el[ctx], args);
                }, 0);
            });
        },
        unbind(el, binding, vnode) {
            // console.warn('执行了unbind钩子,全局validation为', Vue.$validation);
            if (typeof binding.value === 'undefined') return;
            let field = binding.value.key || vnode.context._uid;
            Vue.$validation[field] = {};
        }
    },
    validation = {};

// === install ===

const install = function(Vue) {
    Vue.directive('validator', Validator);
    Vue.$validation = Vue.config.globalProperties.$validation = validation; // 全局数据标识
};

if (!isServer && window.Vue) {
    window.Validator = Validator;
    Vue.use(install); // eslint-disable-line
}

Validator.install = install;
export default Validator;
